Workaround ACL overflow issues by not dropping packets until buffer reaches size of 100.

It seems to work without causing input delays or anything bad.
This commit is contained in:
Jordan Woyak 2013-02-01 19:00:10 -06:00
parent e199d21513
commit e4588e2dfc
2 changed files with 51 additions and 61 deletions

View File

@ -336,23 +336,23 @@ void CWII_IPC_HLE_Device_usb_oh1_57e_305::SendToDevice(u16 _ConnectionHandle, u8
pWiiMote->ExecuteL2capCmd(_pData, _Size); pWiiMote->ExecuteL2capCmd(_pData, _Size);
} }
// Here we send ACL packets to CPU. They will consist of header + data.
// The header is for example 07 00 41 00 which means size 0x0007 and channel 0x0041.
// ---------------------------------------------------
// AyuanX: Basically, our WII_IPC_HLE is efficient enough to send the packet immediately
// rather than enqueue it to some other memory
// But...the only exception comes from the Wiimote_Plugin
void CWII_IPC_HLE_Device_usb_oh1_57e_305::IncDataPacket(u16 _ConnectionHandle) void CWII_IPC_HLE_Device_usb_oh1_57e_305::IncDataPacket(u16 _ConnectionHandle)
{ {
m_PacketCount[_ConnectionHandle & 0xff]++; m_PacketCount[_ConnectionHandle & 0xff]++;
// I don't think this makes sense or should be necessary
// m_PacketCount refers to "completed" packets and is not related to some buffer size, yes?
#if 0
if (m_PacketCount[_ConnectionHandle & 0xff] > (unsigned int)m_acl_pkts_num) if (m_PacketCount[_ConnectionHandle & 0xff] > (unsigned int)m_acl_pkts_num)
{ {
DEBUG_LOG(WII_IPC_WIIMOTE, "ACL buffer overflow"); DEBUG_LOG(WII_IPC_WIIMOTE, "ACL buffer overflow");
m_PacketCount[_ConnectionHandle & 0xff] = m_acl_pkts_num; m_PacketCount[_ConnectionHandle & 0xff] = m_acl_pkts_num;
} }
#endif
} }
// Here we send ACL packets to CPU. They will consist of header + data.
// The header is for example 07 00 41 00 which means size 0x0007 and channel 0x0041.
void CWII_IPC_HLE_Device_usb_oh1_57e_305::SendACLPacket(u16 _ConnectionHandle, u8* _pData, u32 _Size) void CWII_IPC_HLE_Device_usb_oh1_57e_305::SendACLPacket(u16 _ConnectionHandle, u8* _pData, u32 _Size)
{ {
DEBUG_LOG(WII_IPC_WIIMOTE, "ACL packet from %x ready to send to stack...", _ConnectionHandle); DEBUG_LOG(WII_IPC_WIIMOTE, "ACL packet from %x ready to send to stack...", _ConnectionHandle);
@ -374,8 +374,7 @@ void CWII_IPC_HLE_Device_usb_oh1_57e_305::SendACLPacket(u16 _ConnectionHandle, u
} }
else else
{ {
DEBUG_LOG(WII_IPC_WIIMOTE, "ACL endpoint not currently valid, " DEBUG_LOG(WII_IPC_WIIMOTE, "ACL endpoint not currently valid, queueing...");
"queueing(%d)...", m_acl_pool.GetWritePos());
m_acl_pool.Store(_pData, _Size, _ConnectionHandle); m_acl_pool.Store(_pData, _Size, _ConnectionHandle);
} }
} }
@ -518,25 +517,51 @@ u32 CWII_IPC_HLE_Device_usb_oh1_57e_305::Update()
return packet_transferred; return packet_transferred;
} }
void CWII_IPC_HLE_Device_usb_oh1_57e_305::ACLPool::Store(const u8* data, const u16 size, const u16 conn_handle)
{
if (m_queue.size() >= 100)
{
// Many simultaneous exchanges of ACL packets tend to cause the
// queue to fill up. Typically, this occurs when
// many emulated Wiimotes are requesting connections at once.
// See issue 4608 for more info.
ERROR_LOG(WII_IPC_WIIMOTE, "ACL queue size reached 100 - current packet will be "
"dropped! (Hopefully you never see this.)");
return;
}
_dbg_assert_msg_(WII_IPC_WIIMOTE,
size < m_acl_pkt_size, "acl packet too large for pool");
m_queue.push_back(Packet());
auto& packet = m_queue.back();
std::copy_n(data, size, packet.data);
packet.size = size;
packet.conn_handle = conn_handle;
}
void CWII_IPC_HLE_Device_usb_oh1_57e_305::ACLPool::WriteToEndpoint(CtrlBuffer& endpoint) void CWII_IPC_HLE_Device_usb_oh1_57e_305::ACLPool::WriteToEndpoint(CtrlBuffer& endpoint)
{ {
const u8 *data = m_pool + m_acl_pkt_size * m_read_ptr; auto& packet = m_queue.front();
const u16 size = m_info[m_read_ptr].size;
const u16 conn_handle = m_info[m_read_ptr].conn_handle; const u8* const data = packet.data;
const u16 size = packet.size;
const u16 conn_handle = packet.conn_handle;
DEBUG_LOG(WII_IPC_WIIMOTE, "ACL packet being written from " DEBUG_LOG(WII_IPC_WIIMOTE, "ACL packet being written from "
"queue(%d) to %08x", GetReadPos(), endpoint.m_address); "queue to %08x", endpoint.m_address);
hci_acldata_hdr_t* pHeader = (hci_acldata_hdr_t*)Memory::GetPointer(endpoint.m_buffer); hci_acldata_hdr_t* pHeader = (hci_acldata_hdr_t*)Memory::GetPointer(endpoint.m_buffer);
pHeader->con_handle = HCI_MK_CON_HANDLE(conn_handle, HCI_PACKET_START, HCI_POINT2POINT); pHeader->con_handle = HCI_MK_CON_HANDLE(conn_handle, HCI_PACKET_START, HCI_POINT2POINT);
pHeader->length = size; pHeader->length = size;
// Write the packet to the buffer // Write the packet to the buffer
memcpy((u8*)pHeader + sizeof(hci_acldata_hdr_t), data, pHeader->length); std::copy_n(data, pHeader->length, (u8*)pHeader + sizeof(hci_acldata_hdr_t));
endpoint.SetRetVal(sizeof(hci_acldata_hdr_t) + size); endpoint.SetRetVal(sizeof(hci_acldata_hdr_t) + size);
m_read_ptr = (m_read_ptr + 1) % m_acl_pkts_num; m_queue.pop_front();
WII_IPC_HLE_Interface::EnqReply(endpoint.m_address); WII_IPC_HLE_Interface::EnqReply(endpoint.m_address);
endpoint.Invalidate(); endpoint.Invalidate();

View File

@ -17,9 +17,11 @@
#pragma once #pragma once
#include "hci.h" #include <algorithm>
#include <vector> #include <vector>
#include <queue> #include <queue>
#include "hci.h"
#include "WII_IPC_HLE.h" #include "WII_IPC_HLE.h"
#include "WII_IPC_HLE_Device.h" #include "WII_IPC_HLE_Device.h"
#include "WII_IPC_HLE_WiiMote.h" #include "WII_IPC_HLE_WiiMote.h"
@ -168,70 +170,33 @@ private:
class ACLPool class ACLPool
{ {
u8 m_pool[m_acl_pkt_size * m_acl_pkts_num]; struct Packet
int m_read_ptr;
int m_write_ptr;
struct
{ {
u8 data[m_acl_pkt_size];
u16 size; u16 size;
u16 conn_handle; u16 conn_handle;
} m_info[m_acl_pkts_num]; };
std::deque<Packet> m_queue;
public: public:
ACLPool() ACLPool()
: m_read_ptr(0) : m_queue()
, m_write_ptr(0)
{} {}
void Store(const u8* data, const u16 size, const u16 conn_handle) void Store(const u8* data, const u16 size, const u16 conn_handle);
{
_dbg_assert_msg_(WII_IPC_WIIMOTE,
size < m_acl_pkt_size, "acl packet too large for pool");
const int next_write_ptr = (m_write_ptr + 1) % m_acl_pkts_num;
if (next_write_ptr == m_read_ptr)
{
// Many simultaneous exchanges of ACL packets tend to cause the
// 10-packet limit to be exceeded. Typically, this occurs when
// many emulated Wiimotes are requesting connections at once.
// See issue 4608 for more info.
ERROR_LOG(WII_IPC_WIIMOTE, "ACL queue is full - current packet will be "
"dropped! (m_write_ptr(%d) was about to overlap m_read_ptr(%d))",
m_write_ptr, m_read_ptr);
return;
}
memcpy(m_pool + m_acl_pkt_size * m_write_ptr, data, size);
m_info[m_write_ptr].size = size;
m_info[m_write_ptr].conn_handle = conn_handle;
m_write_ptr = next_write_ptr;
}
void WriteToEndpoint(CtrlBuffer& endpoint); void WriteToEndpoint(CtrlBuffer& endpoint);
bool IsEmpty() const bool IsEmpty() const
{ {
return m_write_ptr == m_read_ptr; return m_queue.empty();
}
int GetWritePos() const
{
return m_write_ptr;
}
int GetReadPos() const
{
return m_read_ptr;
} }
// For SaveStates // For SaveStates
void DoState(PointerWrap &p) void DoState(PointerWrap &p)
{ {
p.Do(m_write_ptr); p.Do(m_queue);
p.Do(m_read_ptr);
p.DoArray((u8 *)m_pool, sizeof(m_pool));
p.DoArray((u8 *)m_info, sizeof(m_info));
} }
} m_acl_pool; } m_acl_pool;