USB Serial and SPI with Teensy 4.0
Actually, for a T4.x a data rate of 300kB over the virtual serial port is not demanding at all.
I suggest to use a simple ring buffer (e.g. https://github.com/tonton81/Circular_Buffer) for storage of received data.
To achieve your data transfer requirement (1 block of 40 16bit words every 250µs) it might be best to send out one block of data in a timer ISR and invoke this ISR with 4kHz.
Here some prove of principle code showing how to achieve this:
    #include &quot;SPI.h&quot;
    #include &quot;circular_buffer.h&quot;
    
    Circular_Buffer&lt;uint16_t, 16*1024&gt; ringBuffer;  // adjust buffer size if necessary
    
    constexpr unsigned CS = 0;
    constexpr size_t blockSize = 40;
    
    void sendSPI()
    {
        if (ringBuffer.available() &gt;= blockSize) // send only a complete data block
        {
            SPI.beginTransaction(SPISettings(4'000'000, MSBFIRST, SPI_MODE0));
            digitalWriteFast(CS, LOW); // assuming an active low chip select
            for (unsigned i = 0; i &lt; blockSize; i++)
            {
                SPI.transfer16(ringBuffer.read()); // read one entry from the buffer and send it
            }
            digitalWriteFast(CS, HIGH);
            SPI.endTransaction();
        }
    }
    
    IntervalTimer spiTimer;
    
    void setup()
    {
        pinMode(CS, OUTPUT);
        SPI.begin();        
        spiTimer.begin(sendSPI, 1'000'000 / 4000); // transfer one block every 250µs
    }
    
    uint16_t oldDatum = -1; // error checking, we expect incrementing data from serial
    
    void loop()
    {
        while (Serial.available() &amp;&amp; ringBuffer.available() &lt; ringBuffer.capacity())
        {
            uint16_t datum;
            Serial.readBytes((char*)&amp;datum, 2);
            ringBuffer.write(datum);
    
            uint16_t diff = datum - oldDatum;    
            if(diff != 1)
            {
                SerialUSB1.printf(&quot;Error @%04X\n&quot;, datum);
            }
            oldDatum = datum;
        }    
    }

As long as there is space availabe, the code copies received serial data into the ring buffer. The timer interrupt driven sending part reads a 40word block from the ring buffer and sends it to your device.
To check if any data is lost, the code checks the incoming bytes and prints out any error (data not incrementing) on the second serial connection.
I used the following simple c# application to test the firmware.
    class Program
    {
        static void Main(string[] args)
        {                                                       
            int bufSize = 2 * 64 * 1024;               // generate some dummy data (incrementing 16bit values)
            var data = new byte[bufSize];              // any buffer size would work. I chose 128kB to get a nice data wrap around for the simple error detection in the firmware
            for (int i = 0; i &lt; bufSize / 2; i++)
            {
                var bytes = BitConverter.GetBytes(i);  // convert from uint16 to byte[4]
                data[i * 2] = bytes[0];
                data[i * 2 + 1] = bytes[1];
            }

            // Send out the data as quick as possible, the underlying algorithms will pause sending if the FW doesn't read the bytes from the stream. 
            // -&gt; this is auto syncing the rate with the FW read rate. 
            using (var port = new SerialPort(&quot;COM11&quot;))
            {
                port.Open();
                while (!Console.KeyAvailable)      // stop program on any key press
                {
                    port.Write(data, 0, bufSize);  // send out data, driver will pause if necessary
                }
            }
        }
    }
}


Both, FW and SW work without issue here and I didn't observe any data loss. The underlying PC driver is smart enough to pause sending when the FW is not reading the data from the stream. Thus, you get a synchronization of the sending and  receiving data rate for free.
Here some measurement results for 4MHz SPI frequency:

Zoomed in:

And here a measurement with 32MHz SPI frequency (can't resolve details with my LA at this speed). But you can see that sending one block (80byte) is done in about 32µs.