• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2020-2021 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "los_vm_zone.h"
17 #include "virtmmio.h"
18 
VirtioGetStatus(const struct VirtmmioDev * dev)19 static inline uint32_t VirtioGetStatus(const struct VirtmmioDev *dev)
20 {
21     return GET_UINT32(dev->base + VIRTMMIO_REG_STATUS);
22 }
23 
VirtioAddStatus(const struct VirtmmioDev * dev,uint32_t val)24 static inline void VirtioAddStatus(const struct VirtmmioDev *dev, uint32_t val)
25 {
26     WRITE_UINT32(VirtioGetStatus(dev) | val, dev->base + VIRTMMIO_REG_STATUS);
27 }
28 
VirtioResetStatus(const struct VirtmmioDev * dev)29 static inline void VirtioResetStatus(const struct VirtmmioDev *dev)
30 {
31     WRITE_UINT32(VIRTIO_STATUS_RESET, dev->base + VIRTMMIO_REG_STATUS);
32 }
33 
VirtmmioDiscover(uint32_t devId,struct VirtmmioDev * dev)34 bool VirtmmioDiscover(uint32_t devId, struct VirtmmioDev *dev)
35 {
36     VADDR_T base;
37     int i;
38 
39     base = IO_DEVICE_ADDR(VIRTMMIO_BASE_ADDR) + VIRTMMIO_BASE_SIZE * (NUM_VIRTIO_TRANSPORTS - 1);
40     for (i = NUM_VIRTIO_TRANSPORTS - 1; i >= 0; i--) {
41         if ((GET_UINT32(base + VIRTMMIO_REG_MAGICVALUE) == VIRTMMIO_MAGIC) &&
42             (GET_UINT32(base + VIRTMMIO_REG_VERSION) == VIRTMMIO_VERSION) &&
43             (GET_UINT32(base + VIRTMMIO_REG_DEVICEID) == devId)) {
44             dev->base = base;
45             dev->irq = IRQ_SPI_BASE + VIRTMMIO_BASE_IRQ + i;
46             return true;
47         }
48 
49         base -= VIRTMMIO_BASE_SIZE;
50     }
51 
52     PRINT_ERR("virtio-mmio ID=%u device not found\n", devId);
53     return false;
54 }
55 
VirtqSize(uint16_t qsz)56 unsigned VirtqSize(uint16_t qsz)
57 {
58            /* pretend we do not have an aligned start address */
59     return VIRTQ_ALIGN_DESC - 1 +
60            ALIGN(sizeof(struct VirtqDesc) * qsz, VIRTQ_ALIGN_AVAIL) +
61            ALIGN(sizeof(struct VirtqAvail) + sizeof(uint16_t) * qsz, VIRTQ_ALIGN_USED) +
62            sizeof(struct VirtqUsed) + sizeof(struct VirtqUsedElem) * qsz;
63 }
64 
VirtmmioInitBegin(const struct VirtmmioDev * dev)65 void VirtmmioInitBegin(const struct VirtmmioDev *dev)
66 {
67     VirtioResetStatus(dev);
68     VirtioAddStatus(dev, VIRTIO_STATUS_ACK);
69     VirtioAddStatus(dev, VIRTIO_STATUS_DRIVER);
70     while ((VirtioGetStatus(dev) & VIRTIO_STATUS_DRIVER) == 0) { }
71 }
72 
VritmmioInitEnd(const struct VirtmmioDev * dev)73 void VritmmioInitEnd(const struct VirtmmioDev *dev)
74 {
75     VirtioAddStatus(dev, VIRTIO_STATUS_DRIVER_OK);
76 }
77 
VirtmmioInitFailed(const struct VirtmmioDev * dev)78 void VirtmmioInitFailed(const struct VirtmmioDev *dev)
79 {
80     VirtioAddStatus(dev, VIRTIO_STATUS_FAILED);
81 }
82 
Negotiate(struct VirtmmioDev * baseDev,uint32_t nth,VirtioFeatureFn fn,void * dev)83 static bool Negotiate(struct VirtmmioDev *baseDev, uint32_t nth, VirtioFeatureFn fn, void *dev)
84 {
85     uint32_t features, supported, before, after;
86 
87     WRITE_UINT32(nth, baseDev->base + VIRTMMIO_REG_DEVFEATURESEL);
88     features = GET_UINT32(baseDev->base + VIRTMMIO_REG_DEVFEATURE);
89 
90     do {
91         before = GET_UINT32(baseDev->base + VIRTMMIO_REG_CONFIGGENERATION);
92 
93         supported = 0;
94         if (!fn(features, &supported, dev)) {
95             return false;
96         }
97 
98         after = GET_UINT32(baseDev->base + VIRTMMIO_REG_CONFIGGENERATION);
99     } while (before != after);
100 
101     WRITE_UINT32(nth, baseDev->base + VIRTMMIO_REG_DRVFEATURESEL);
102     WRITE_UINT32(supported, baseDev->base + VIRTMMIO_REG_DRVFEATURE);
103     return true;
104 }
105 
VirtmmioNegotiate(struct VirtmmioDev * baseDev,VirtioFeatureFn f0,VirtioFeatureFn f1,void * dev)106 bool VirtmmioNegotiate(struct VirtmmioDev *baseDev, VirtioFeatureFn f0, VirtioFeatureFn f1, void *dev)
107 {
108     if(!Negotiate(baseDev, VIRTIO_FEATURE_WORD0, f0, dev)) {
109         return false;
110     }
111 
112     if(!Negotiate(baseDev, VIRTIO_FEATURE_WORD1, f1, dev)) {
113         return false;
114     }
115 
116     VirtioAddStatus(baseDev, VIRTIO_STATUS_FEATURES_OK);
117     if ((VirtioGetStatus(baseDev) & VIRTIO_STATUS_FEATURES_OK) == 0) {
118         PRINT_ERR("negotiate features failed\n");
119         return false;
120     }
121 
122     return true;
123 }
124 
125 #define U32_MASK        0xFFFFFFFF
126 #define U32_BYTES       4
127 #define U64_32_SHIFT    32
WriteQueueAddr(uint64_t addr,const struct VirtmmioDev * dev,uint32_t regLow)128 static void WriteQueueAddr(uint64_t addr, const struct VirtmmioDev *dev, uint32_t regLow)
129 {
130     uint32_t paddr;
131 
132     addr = VMM_TO_DMA_ADDR(addr);
133     paddr = addr & U32_MASK;
134     WRITE_UINT32(paddr, dev->base + regLow);
135     paddr = addr >> U64_32_SHIFT;
136     WRITE_UINT32(paddr, dev->base + regLow + U32_BYTES);
137 }
138 
CompleteConfigQueue(uint32_t queue,const struct VirtmmioDev * dev)139 static bool CompleteConfigQueue(uint32_t queue, const struct VirtmmioDev *dev)
140 {
141     const struct Virtq *q = &dev->vq[queue];
142     uint32_t num;
143 
144     WRITE_UINT32(queue, dev->base + VIRTMMIO_REG_QUEUESEL);
145 
146     num = GET_UINT32(dev->base + VIRTMMIO_REG_QUEUEREADY);
147     LOS_ASSERT(num == 0);
148     num = GET_UINT32(dev->base + VIRTMMIO_REG_QUEUENUMMAX);
149     if (num < q->qsz) {
150         PRINT_ERR("queue %u not available: max qsz=%u, requested=%u\n", queue, num, q->qsz);
151         return false;
152     }
153 
154     WRITE_UINT32(q->qsz, dev->base + VIRTMMIO_REG_QUEUENUM);
155     WriteQueueAddr((uint64_t)q->desc, dev, VIRTMMIO_REG_QUEUEDESCLOW);
156     WriteQueueAddr((uint64_t)q->avail, dev, VIRTMMIO_REG_QUEUEDRIVERLOW);
157     WriteQueueAddr((uint64_t)q->used, dev, VIRTMMIO_REG_QUEUEDEVICELOW);
158 
159     WRITE_UINT32(1, dev->base + VIRTMMIO_REG_QUEUEREADY);
160     return true;
161 }
162 
CalculateQueueAddr(VADDR_T base,uint16_t qsz,struct Virtq * q)163 static VADDR_T CalculateQueueAddr(VADDR_T base, uint16_t qsz, struct Virtq *q)
164 {
165     base = ALIGN(base, VIRTQ_ALIGN_DESC);
166     q->desc = (struct VirtqDesc *)base;
167     q->qsz = qsz;
168     base = ALIGN(base + sizeof(struct VirtqDesc) * qsz, VIRTQ_ALIGN_AVAIL);
169     q->avail = (struct VirtqAvail *)base;
170     base = ALIGN(base + sizeof(struct VirtqAvail) + sizeof(uint16_t) * qsz, VIRTQ_ALIGN_USED);
171     q->used = (struct VirtqUsed *)base;
172 
173     return base + sizeof(struct VirtqUsed) + sizeof(struct VirtqUsedElem) * qsz;
174 }
175 
VirtmmioConfigQueue(struct VirtmmioDev * dev,VADDR_T base,uint16_t qsz[],int num)176 VADDR_T VirtmmioConfigQueue(struct VirtmmioDev *dev, VADDR_T base, uint16_t qsz[], int num)
177 {
178     uint32_t i;
179 
180     for (i = 0; i < num; i++) {
181         base = CalculateQueueAddr(base, qsz[i], &dev->vq[i]);
182         if (!CompleteConfigQueue(i, dev)) {
183             return 0;
184         }
185     }
186 
187     return base;
188 }
189 
VirtmmioRegisterIRQ(struct VirtmmioDev * dev,HWI_PROC_FUNC handle,void * argDev,const char * devName)190 bool VirtmmioRegisterIRQ(struct VirtmmioDev *dev, HWI_PROC_FUNC handle, void *argDev, const char *devName)
191 {
192     uint32_t ret;
193     HwiIrqParam param = {0, argDev, devName};
194 
195     ret = LOS_HwiCreate(dev->irq, OS_HWI_PRIO_HIGHEST, IRQF_SHARED, handle, &param);
196     if (ret != 0) {
197         PRINT_ERR("virtio-mmio %s IRQ register failed: %u\n", devName, ret);
198         return false;
199     }
200 
201     HalIrqUnmask(dev->irq);
202     dev->irq |= ~_IRQ_MASK;
203     return true;
204 }
205