• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2023 Huawei Device Co., Ltd.
3  *
4  * HDF is dual licensed: you can use it either under the terms of
5  * the GPL, or the BSD license, at your option.
6  * See the LICENSE file in the root of this repository for complete details.
7  */
8 
9 #include "pcie_dispatch.h"
10 #include "hdf_log.h"
11 #include "osal_mem.h"
12 #include "pcie_core.h"
13 #include "pcie_if.h"
14 #include "platform_listener_common.h"
15 
16 #define HDF_LOG_TAG pcie_dispatch_c
17 #define IRQ_CB_NUM      0
18 #define DMA_CB_NUM      1
19 #define USER_LEM_MAX    4096
20 #define DMA_ALIGN_SIZE  256
21 
22 enum PcieIoCmd {
23     PCIE_CMD_READ = 0,
24     PCIE_CMD_WRITE,
25     PCIE_CMD_DMA_MAP,
26     PCIE_CMD_DMA_UNMAP,
27     PCIE_CMD_REG_IRQ,
28     PCIE_CMD_UNREG_IRQ,
29     PCIE_CMD_BUTT,
30 };
31 
PcieCmdRead(struct PcieCntlr * cntlr,struct HdfSBuf * data,struct HdfSBuf * reply)32 static int32_t PcieCmdRead(struct PcieCntlr *cntlr, struct HdfSBuf *data, struct HdfSBuf *reply)
33 {
34     uint32_t mode;
35     uint32_t len;
36     uint32_t pos;
37     uint8_t *buf = NULL;
38     int32_t ret;
39 
40     if (!HdfSbufReadUint32(data, &mode)) {
41         HDF_LOGE("PcieCmdRead: read mode fail");
42         return HDF_ERR_IO;
43     }
44     if (!HdfSbufReadUint32(data, &len)) {
45         HDF_LOGE("PcieCmdRead: read len fail");
46         return HDF_ERR_IO;
47     }
48     if (len == 0 ||  len > USER_LEM_MAX) {
49         HDF_LOGE("PcieCmdRead: invalid len");
50         return HDF_ERR_INVALID_PARAM;
51     }
52     if (!HdfSbufReadUint32(data, &pos)) {
53         HDF_LOGE("PcieCmdRead: read pos fail");
54         return HDF_ERR_IO;
55     }
56 
57     buf = (uint8_t *)OsalMemCalloc(sizeof(*buf) * len);
58     if (buf == NULL) {
59         HDF_LOGE("PcieCmdRead: OsalMemCalloc error");
60         return HDF_ERR_MALLOC_FAIL;
61     }
62 
63     ret = PcieCntlrRead(cntlr, mode, pos, buf, len);
64     if (ret != HDF_SUCCESS) {
65         HDF_LOGE("PcieCmdRead: error, ret is %d", ret);
66         OsalMemFree(buf);
67         return ret;
68     }
69     if (!HdfSbufWriteBuffer(reply, buf, len)) {
70         HDF_LOGE("PcieCmdRead: sbuf write buffer fail!");
71         OsalMemFree(buf);
72         return HDF_ERR_IO;
73     }
74 
75     OsalMemFree(buf);
76     return HDF_SUCCESS;
77 }
78 
PcieCmdWrite(struct PcieCntlr * cntlr,struct HdfSBuf * data)79 static int32_t PcieCmdWrite(struct PcieCntlr *cntlr, struct HdfSBuf *data)
80 {
81     uint32_t pos;
82     uint32_t len;
83     uint32_t size;
84     uint32_t mode;
85     uint8_t *buf = NULL;
86 
87     if (!HdfSbufReadUint32(data, &mode)) {
88         HDF_LOGE("PcieCmdWrite: read pos fail");
89         return HDF_ERR_IO;
90     }
91     if (!HdfSbufReadUint32(data, &len)) {
92         HDF_LOGE("PcieCmdWrite: read pos fail");
93         return HDF_ERR_IO;
94     }
95     if (!HdfSbufReadUint32(data, &pos)) {
96         HDF_LOGE("PcieCmdWrite: read pos fail");
97         return HDF_ERR_IO;
98     }
99     if (!HdfSbufReadBuffer(data, (const void **)&buf, &size)) {
100         HDF_LOGE("PcieCmdWrite: sbuf read buffer fail!");
101         return HDF_ERR_IO;
102     }
103     if (len == 0 || len != size) {
104         HDF_LOGE("PcieCmdWrite: read sbuf error");
105         return HDF_ERR_IO;
106     }
107     return PcieCntlrWrite(cntlr, mode, pos, buf, len);
108 }
109 
PcieIoDmaCb(DevHandle handle)110 static int32_t PcieIoDmaCb(DevHandle handle)
111 {
112     struct HdfSBuf *data = NULL;
113     struct PcieCntlr *cntlr = (struct PcieCntlr *)handle;
114     int32_t ret;
115 
116     if (cntlr == NULL) {
117         HDF_LOGE("PcieIoDmaCb: cntlr is null!");
118         return HDF_ERR_INVALID_PARAM;
119     }
120 
121     data = HdfSbufObtainDefaultSize();
122     if (data == NULL) {
123         HDF_LOGE("PcieIoDmaCb: fail to obtain data!");
124         return HDF_ERR_MALLOC_FAIL;
125     }
126     if (!HdfSbufWriteUint32(data, DMA_CB_NUM)) {
127         HDF_LOGE("PcieIoDmaCb: sbuf write num fail!");
128         HdfSbufRecycle(data);
129         return HDF_ERR_IO;
130     }
131     if (cntlr->dir == PCIE_DMA_FROM_DEVICE) {
132         if (!HdfSbufWriteBuffer(data, (const void *)cntlr->dmaData, cntlr->len)) {
133             HDF_LOGE("PcieIoDmaCb: sbuf write buffer fail!");
134             HdfSbufRecycle(data);
135             return HDF_ERR_IO;
136         }
137     }
138     ret = HdfDeviceSendEvent(cntlr->hdfDevObj, PLATFORM_LISTENER_EVENT_PCIE_NOTIFY, data);
139     if (ret != HDF_SUCCESS) {
140         HDF_LOGE("PcieIoDmaCb: send event fail");
141     }
142 
143     HdfSbufRecycle(data);
144     return ret;
145 }
146 
DmaToDevice(struct PcieCntlr * cntlr,struct HdfSBuf * data,uint32_t len)147 static int32_t DmaToDevice(struct PcieCntlr *cntlr, struct HdfSBuf *data, uint32_t len)
148 {
149     uint8_t *buf = NULL;
150     uint32_t size;
151 
152     if (!HdfSbufReadBuffer(data, (const void **)&buf, &size) || size != len) {
153         HDF_LOGE("DmaToDevice: sbuf read buffer fail!");
154         return HDF_ERR_IO;
155     }
156     cntlr->dmaData = (uintptr_t)buf;
157     cntlr->len = len;
158     cntlr->dir = PCIE_DMA_TO_DEVICE;
159 
160     return PcieCntlrDmaMap(cntlr, PcieIoDmaCb, (uintptr_t)buf, len, PCIE_DMA_TO_DEVICE);
161 }
162 
DeviceToDma(struct PcieCntlr * cntlr,uint32_t len)163 static int32_t DeviceToDma(struct PcieCntlr *cntlr, uint32_t len)
164 {
165     uint8_t *addr = NULL;
166 
167     addr = OsalMemAllocAlign(DMA_ALIGN_SIZE, len);
168     if (addr == NULL) {
169         HDF_LOGE("DeviceToDma: malloc fail");
170         return HDF_ERR_MALLOC_FAIL;
171     }
172     cntlr->dmaData = (uintptr_t)addr;
173     cntlr->len = len;
174     cntlr->dir = PCIE_DMA_FROM_DEVICE;
175 
176     return PcieCntlrDmaMap(cntlr, PcieIoDmaCb, (uintptr_t)addr, len, PCIE_DMA_FROM_DEVICE);
177 }
178 
PcieCmdDmaMap(struct PcieCntlr * cntlr,struct HdfSBuf * data)179 static int32_t PcieCmdDmaMap(struct PcieCntlr *cntlr, struct HdfSBuf *data)
180 {
181     int32_t ret;
182     uint32_t len;
183     uint8_t dir;
184 
185     if (!HdfSbufReadUint8(data, &dir)) {
186         HDF_LOGE("PcieCmdDmaMap: read dir fail");
187         return HDF_ERR_IO;
188     }
189     if (!HdfSbufReadUint32(data, &len)) {
190         HDF_LOGE("PcieCmdDmaMap: read len fail");
191         return HDF_ERR_IO;
192     }
193     if (len == 0 || len > USER_LEM_MAX) {
194         HDF_LOGE("PcieCmdDmaMap: invalid len");
195         return HDF_ERR_INVALID_PARAM;
196     }
197     if (cntlr->dmaData != 0 || cntlr->len != 0) {
198         return HDF_ERR_DEVICE_BUSY;
199     }
200     if (dir == PCIE_DMA_FROM_DEVICE) {
201         ret = DeviceToDma(cntlr, len);
202     } else if (dir == PCIE_DMA_TO_DEVICE) {
203         ret = DmaToDevice(cntlr, data, len);
204     } else {
205         HDF_LOGE("PcieCmdDmaMap: invalid dir");
206         ret = HDF_ERR_INVALID_PARAM;
207     }
208 
209     return ret;
210 }
211 
PcieCmdDmaUnmap(struct PcieCntlr * cntlr,struct HdfSBuf * data)212 static int32_t PcieCmdDmaUnmap(struct PcieCntlr *cntlr, struct HdfSBuf *data)
213 {
214     uint8_t dir;
215 
216     if (!HdfSbufReadUint8(data, &dir) || dir != cntlr->dir) {
217         HDF_LOGE("PcieCmdDmaUnmap: read dir fail");
218         return HDF_ERR_IO;
219     }
220 
221     PcieCntlrDmaUnmap(cntlr, cntlr->dmaData, cntlr->len, dir);
222     OsalMemFree((void *)cntlr->dmaData);
223     cntlr->dmaData = 0;
224     cntlr->len = 0;
225 
226     return HDF_SUCCESS;
227 }
228 
PcieIoCallback(DevHandle handle)229 static int32_t PcieIoCallback(DevHandle handle)
230 {
231     struct HdfSBuf *data = NULL;
232     struct PcieCntlr *cntlr = (struct PcieCntlr *)handle;
233     int32_t ret;
234 
235     if (cntlr == NULL) {
236         HDF_LOGE("PcieIoCallback: cntlr is null!");
237         return HDF_ERR_INVALID_PARAM;
238     }
239 
240     data = HdfSbufObtainDefaultSize();
241     if (data == NULL) {
242         HDF_LOGE("PcieIoCallback: fail to obtain data!");
243         return HDF_ERR_MALLOC_FAIL;
244     }
245     if (!HdfSbufWriteUint32(data, IRQ_CB_NUM)) {
246         HDF_LOGE("PcieIoCallback: sbuf write num fail!");
247         HdfSbufRecycle(data);
248         return HDF_ERR_IO;
249     }
250 
251     ret = HdfDeviceSendEvent(cntlr->hdfDevObj, PLATFORM_LISTENER_EVENT_PCIE_NOTIFY, data);
252     HdfSbufRecycle(data);
253     return ret;
254 }
255 
PcieCmdRegisterIrq(struct PcieCntlr * cntlr)256 static int32_t PcieCmdRegisterIrq(struct PcieCntlr *cntlr)
257 {
258     return PcieCntlrRegisterIrq(cntlr, PcieIoCallback);
259 }
260 
PcieCmdUnregisterIrq(struct PcieCntlr * cntlr)261 static int32_t PcieCmdUnregisterIrq(struct PcieCntlr *cntlr)
262 {
263     PcieCntlrUnregisterIrq(cntlr);
264     return HDF_SUCCESS;
265 }
266 
PcieIoDispatch(struct HdfDeviceIoClient * client,int32_t cmd,struct HdfSBuf * data,struct HdfSBuf * reply)267 int32_t PcieIoDispatch(struct HdfDeviceIoClient *client, int32_t cmd, struct HdfSBuf *data, struct HdfSBuf *reply)
268 {
269     struct PcieCntlr *cntlr = NULL;
270 
271     if (client == NULL || client->device == NULL) {
272         HDF_LOGE("PcieIoDispatch: client or hdf dev obj is null!");
273         return HDF_ERR_INVALID_OBJECT;
274     }
275 
276     cntlr = (struct PcieCntlr *)client->device->service;
277     if (cntlr == NULL) {
278         HDF_LOGE("PcieIoDispatch: service is null!");
279         return HDF_ERR_INVALID_OBJECT;
280     }
281 
282     switch (cmd) {
283         case PCIE_CMD_READ:
284             return PcieCmdRead(cntlr, data, reply);
285         case PCIE_CMD_WRITE:
286             return PcieCmdWrite(cntlr, data);
287         case PCIE_CMD_DMA_MAP:
288             return PcieCmdDmaMap(cntlr, data);
289         case PCIE_CMD_DMA_UNMAP:
290             return PcieCmdDmaUnmap(cntlr, data);
291         case PCIE_CMD_REG_IRQ:
292             return PcieCmdRegisterIrq(cntlr);
293         case PCIE_CMD_UNREG_IRQ:
294             return PcieCmdUnregisterIrq(cntlr);
295         default:
296             HDF_LOGE("PcieIoDispatch: cmd %d is not support", cmd);
297             return HDF_ERR_NOT_SUPPORT;
298     }
299 
300     return HDF_SUCCESS;
301 }
302