Fix offloaded cache device mismatch on hybrid models
Author: Sunt-ing
Pull request: yes


# What does this PR do?

The offloaded cache (`cache_implementation="offloaded"`) moves each layer's KV to CPU after its `update` and prefetches the next layer back to the accelerator ahead of time. Only attention layers go through this offloading `update` path; linear-attention (Mamba/SSM) layers keep their own small conv/recurrent states and are never offloaded or prefetched.

`Cache.prefetch` picked the prefetch target as the next layer in index order (for `DynamicCache`, `offload_only_non_sliding` defaults to `False`, so it just took `layer_idx + 1`). On a hybrid model that interleaves attention and linear-attention layers, the attention layers are sparse and separated by linear-attention layers, so the prefetch kept landing on the interleaved linear-attention layer (a no-op) and never brought the next attention layer's KV back. After prefill every attention layer's KV is stranded on CPU, and the first decoding `update` then concatenates a CPU cache with a freshly computed accelerator tensor, raising `RuntimeError: Expected all tensors to be on the same device ... cuda:0 ... cpu`. Pure-attention models are unaffected because their layers are contiguous, so the next layer is always the next one that is updated.

The fix makes `prefetch` skip layers that are not offloaded (linear-attention layers, plus sliding layers when `only_non_sliding`) and target the next attention layer that actually goes through the offloading `update` path, wrapping around to the beginning if needed. This is a no-op for non-hybrid caches.

There is no existing issue for this; it was found while running hybrid models (e.g. Qwen3.5) with `cache_implementation="offloaded"`. The parametrized cache tests skip the `offloaded` implementation, so the hybrid path was uncovered; this PR adds a small regression test.

<details>
<summary>Reproduction and before/after</summary>

Environment: `transformers` 5.13.0.dev0 (main), Python 3.12.3, PyTorch 2.8.0+cu128, NVIDIA RTX 4090 (CUDA 12.8).

```python
import torch
from transformers import AutoModelForCausalLM, AutoTokenizer

mid = "Qwen/Qwen3.5-0.8B"
tok = AutoTokenizer.from_pretrained(mid)
m = AutoModelForCausalLM.from_pretrained(mid, dtype=torch.float32).cuda().eval()
ids = tok("The capital of France is", return_tensors="pt").input_ids.cuda()

dyn = m.generate(ids, max_new_tokens=24, do_sample=False)[0, ids.shape[1]:]
off = m.generate(ids, max_new_tokens=24, do_sample=False, cache_implementation="offloaded")[0, ids.shape[1]:]
print("identical:", torch.equal(dyn.cpu(), off.cpu()))
```

Before this PR the `offloaded` generation raises the `RuntimeError`. After it, generation succeeds and is token-identical to the default `DynamicCache` (`identical: True`). A pure-attention model (`Qwen/Qwen3-0.6B`) is identical before and after.

New regression test (passes after, fails before with the device mismatch):

```
tests/utils/test_cache_utils.py -k test_offloaded_cache_prefetches_across_linear_attention_layers
```
</details>

## Code Agent Policy

- [x] I confirm that this is not a pure code agent PR.

## Before submitting
- [ ] This PR fixes a typo or improves the docs (you can dismiss the other checks if that's the case).
- [x] Did you read the [contributor guideline](https://github.com/huggingface/transformers/blob/main/CONTRIBUTING.md#create-a-pull-request), Pull Request section?
- [ ] Was this discussed/approved via a Github issue or the [forum](https://discuss.huggingface.co/)? Please add a link to it if that's the case.
- [ ] Did you make sure to update the documentation with your changes?
- [x] Did you write any new necessary tests?

## Who can review?

cc @Cyrilvallez


Comments:
cc @cyrilvallez @zucchini-nlp for generation cache

@zucchini-nlp Done. One small note: I kept the sliding skip (`not (only_non_sliding and is_sliding)`) so offloaded caches with sliding-window layers still prefetch exactly the same layers as before. The only behavioral change is the hybrid (linear-attention) case.

**CI Dashboard:** [View test results in Grafana](https://transformers-ci.lor-e.huggingface.cool/d/pytest-observability-by-pr/pytest-observability-branch?var-pr=46748)

The docs for this PR live [here](https://moon-ci-docs.huggingface.co/docs/transformers/pr_46748). All of your documentation changes will be reflected on that endpoint. The docs are available until 30 days after the last update.