1 /* 2 * Driver for the NXP SAA7164 PCIe bridge 3 * 4 * Copyright (c) 2010-2015 Steven Toth <stoth@kernellabs.com> 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2 of the License, or 9 * (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * 15 * GNU General Public License for more details. 16 */ 17 18 #include "saa7164.h" 19 20 /* The message bus to/from the firmware is a ring buffer in PCI address 21 * space. Establish the defaults. 22 */ 23 int saa7164_bus_setup(struct saa7164_dev *dev) 24 { 25 struct tmComResBusInfo *b = &dev->bus; 26 27 mutex_init(&b->lock); 28 29 b->Type = TYPE_BUS_PCIe; 30 b->m_wMaxReqSize = SAA_DEVICE_MAXREQUESTSIZE; 31 32 b->m_pdwSetRing = (u8 __iomem *)(dev->bmmio + 33 ((u32)dev->busdesc.CommandRing)); 34 35 b->m_dwSizeSetRing = SAA_DEVICE_BUFFERBLOCKSIZE; 36 37 b->m_pdwGetRing = (u8 __iomem *)(dev->bmmio + 38 ((u32)dev->busdesc.ResponseRing)); 39 40 b->m_dwSizeGetRing = SAA_DEVICE_BUFFERBLOCKSIZE; 41 42 b->m_dwSetWritePos = ((u32)dev->intfdesc.BARLocation) + 43 (2 * sizeof(u64)); 44 b->m_dwSetReadPos = b->m_dwSetWritePos + (1 * sizeof(u32)); 45 46 b->m_dwGetWritePos = b->m_dwSetWritePos + (2 * sizeof(u32)); 47 b->m_dwGetReadPos = b->m_dwSetWritePos + (3 * sizeof(u32)); 48 49 return 0; 50 } 51 52 void saa7164_bus_dump(struct saa7164_dev *dev) 53 { 54 struct tmComResBusInfo *b = &dev->bus; 55 56 dprintk(DBGLVL_BUS, "Dumping the bus structure:\n"); 57 dprintk(DBGLVL_BUS, " .type = %d\n", b->Type); 58 dprintk(DBGLVL_BUS, " .dev->bmmio = 0x%p\n", dev->bmmio); 59 dprintk(DBGLVL_BUS, " .m_wMaxReqSize = 0x%x\n", b->m_wMaxReqSize); 60 dprintk(DBGLVL_BUS, " .m_pdwSetRing = 0x%p\n", b->m_pdwSetRing); 61 dprintk(DBGLVL_BUS, " .m_dwSizeSetRing = 0x%x\n", b->m_dwSizeSetRing); 62 dprintk(DBGLVL_BUS, " .m_pdwGetRing = 0x%p\n", b->m_pdwGetRing); 63 dprintk(DBGLVL_BUS, " .m_dwSizeGetRing = 0x%x\n", b->m_dwSizeGetRing); 64 65 dprintk(DBGLVL_BUS, " .m_dwSetReadPos = 0x%x (0x%08x)\n", 66 b->m_dwSetReadPos, saa7164_readl(b->m_dwSetReadPos)); 67 68 dprintk(DBGLVL_BUS, " .m_dwSetWritePos = 0x%x (0x%08x)\n", 69 b->m_dwSetWritePos, saa7164_readl(b->m_dwSetWritePos)); 70 71 dprintk(DBGLVL_BUS, " .m_dwGetReadPos = 0x%x (0x%08x)\n", 72 b->m_dwGetReadPos, saa7164_readl(b->m_dwGetReadPos)); 73 74 dprintk(DBGLVL_BUS, " .m_dwGetWritePos = 0x%x (0x%08x)\n", 75 b->m_dwGetWritePos, saa7164_readl(b->m_dwGetWritePos)); 76 77 } 78 79 /* Intensionally throw a BUG() if the state of the message bus looks corrupt */ 80 static void saa7164_bus_verify(struct saa7164_dev *dev) 81 { 82 struct tmComResBusInfo *b = &dev->bus; 83 int bug = 0; 84 85 if (saa7164_readl(b->m_dwSetReadPos) > b->m_dwSizeSetRing) 86 bug++; 87 88 if (saa7164_readl(b->m_dwSetWritePos) > b->m_dwSizeSetRing) 89 bug++; 90 91 if (saa7164_readl(b->m_dwGetReadPos) > b->m_dwSizeGetRing) 92 bug++; 93 94 if (saa7164_readl(b->m_dwGetWritePos) > b->m_dwSizeGetRing) 95 bug++; 96 97 if (bug) { 98 saa_debug = 0xffff; /* Ensure we get the bus dump */ 99 saa7164_bus_dump(dev); 100 saa_debug = 1024; /* Ensure we get the bus dump */ 101 BUG(); 102 } 103 } 104 105 static void saa7164_bus_dumpmsg(struct saa7164_dev *dev, struct tmComResInfo *m, 106 void *buf) 107 { 108 dprintk(DBGLVL_BUS, "Dumping msg structure:\n"); 109 dprintk(DBGLVL_BUS, " .id = %d\n", m->id); 110 dprintk(DBGLVL_BUS, " .flags = 0x%x\n", m->flags); 111 dprintk(DBGLVL_BUS, " .size = 0x%x\n", m->size); 112 dprintk(DBGLVL_BUS, " .command = 0x%x\n", m->command); 113 dprintk(DBGLVL_BUS, " .controlselector = 0x%x\n", m->controlselector); 114 dprintk(DBGLVL_BUS, " .seqno = %d\n", m->seqno); 115 if (buf) 116 dprintk(DBGLVL_BUS, " .buffer (ignored)\n"); 117 } 118 119 /* 120 * Places a command or a response on the bus. The implementation does not 121 * know if it is a command or a response it just places the data on the 122 * bus depending on the bus information given in the struct tmComResBusInfo 123 * structure. If the command or response does not fit into the bus ring 124 * buffer it will be refused. 125 * 126 * Return Value: 127 * SAA_OK The function executed successfully. 128 * < 0 One or more members are not initialized. 129 */ 130 int saa7164_bus_set(struct saa7164_dev *dev, struct tmComResInfo* msg, 131 void *buf) 132 { 133 struct tmComResBusInfo *bus = &dev->bus; 134 u32 bytes_to_write, free_write_space, timeout, curr_srp, curr_swp; 135 u32 new_swp, space_rem; 136 int ret = SAA_ERR_BAD_PARAMETER; 137 u16 size; 138 139 if (!msg) { 140 printk(KERN_ERR "%s() !msg\n", __func__); 141 return SAA_ERR_BAD_PARAMETER; 142 } 143 144 dprintk(DBGLVL_BUS, "%s()\n", __func__); 145 146 saa7164_bus_verify(dev); 147 148 if (msg->size > dev->bus.m_wMaxReqSize) { 149 printk(KERN_ERR "%s() Exceeded dev->bus.m_wMaxReqSize\n", 150 __func__); 151 return SAA_ERR_BAD_PARAMETER; 152 } 153 154 if ((msg->size > 0) && (buf == NULL)) { 155 printk(KERN_ERR "%s() Missing message buffer\n", __func__); 156 return SAA_ERR_BAD_PARAMETER; 157 } 158 159 /* Lock the bus from any other access */ 160 mutex_lock(&bus->lock); 161 162 bytes_to_write = sizeof(*msg) + msg->size; 163 free_write_space = 0; 164 timeout = SAA_BUS_TIMEOUT; 165 curr_srp = saa7164_readl(bus->m_dwSetReadPos); 166 curr_swp = saa7164_readl(bus->m_dwSetWritePos); 167 168 /* Deal with ring wrapping issues */ 169 if (curr_srp > curr_swp) 170 /* Deal with the wrapped ring */ 171 free_write_space = curr_srp - curr_swp; 172 else 173 /* The ring has not wrapped yet */ 174 free_write_space = (curr_srp + bus->m_dwSizeSetRing) - curr_swp; 175 176 dprintk(DBGLVL_BUS, "%s() bytes_to_write = %d\n", __func__, 177 bytes_to_write); 178 179 dprintk(DBGLVL_BUS, "%s() free_write_space = %d\n", __func__, 180 free_write_space); 181 182 dprintk(DBGLVL_BUS, "%s() curr_srp = %x\n", __func__, curr_srp); 183 dprintk(DBGLVL_BUS, "%s() curr_swp = %x\n", __func__, curr_swp); 184 185 /* Process the msg and write the content onto the bus */ 186 while (bytes_to_write >= free_write_space) { 187 188 if (timeout-- == 0) { 189 printk(KERN_ERR "%s() bus timeout\n", __func__); 190 ret = SAA_ERR_NO_RESOURCES; 191 goto out; 192 } 193 194 /* TODO: Review this delay, efficient? */ 195 /* Wait, allowing the hardware fetch time */ 196 mdelay(1); 197 198 /* Check the space usage again */ 199 curr_srp = saa7164_readl(bus->m_dwSetReadPos); 200 201 /* Deal with ring wrapping issues */ 202 if (curr_srp > curr_swp) 203 /* Deal with the wrapped ring */ 204 free_write_space = curr_srp - curr_swp; 205 else 206 /* Read didn't wrap around the buffer */ 207 free_write_space = (curr_srp + bus->m_dwSizeSetRing) - 208 curr_swp; 209 210 } 211 212 /* Calculate the new write position */ 213 new_swp = curr_swp + bytes_to_write; 214 215 dprintk(DBGLVL_BUS, "%s() new_swp = %x\n", __func__, new_swp); 216 dprintk(DBGLVL_BUS, "%s() bus->m_dwSizeSetRing = %x\n", __func__, 217 bus->m_dwSizeSetRing); 218 219 /* 220 * Make a copy of msg->size before it is converted to le16 since it is 221 * used in the code below. 222 */ 223 size = msg->size; 224 /* Convert to le16/le32 */ 225 msg->size = (__force u16)cpu_to_le16(msg->size); 226 msg->command = (__force u32)cpu_to_le32(msg->command); 227 msg->controlselector = (__force u16)cpu_to_le16(msg->controlselector); 228 229 /* Mental Note: line 462 tmmhComResBusPCIe.cpp */ 230 231 /* Check if we're going to wrap again */ 232 if (new_swp > bus->m_dwSizeSetRing) { 233 234 /* Ring wraps */ 235 new_swp -= bus->m_dwSizeSetRing; 236 237 space_rem = bus->m_dwSizeSetRing - curr_swp; 238 239 dprintk(DBGLVL_BUS, "%s() space_rem = %x\n", __func__, 240 space_rem); 241 242 dprintk(DBGLVL_BUS, "%s() sizeof(*msg) = %d\n", __func__, 243 (u32)sizeof(*msg)); 244 245 if (space_rem < sizeof(*msg)) { 246 dprintk(DBGLVL_BUS, "%s() tr4\n", __func__); 247 248 /* Split the msg into pieces as the ring wraps */ 249 memcpy_toio(bus->m_pdwSetRing + curr_swp, msg, space_rem); 250 memcpy_toio(bus->m_pdwSetRing, (u8 *)msg + space_rem, 251 sizeof(*msg) - space_rem); 252 253 memcpy_toio(bus->m_pdwSetRing + sizeof(*msg) - space_rem, 254 buf, size); 255 256 } else if (space_rem == sizeof(*msg)) { 257 dprintk(DBGLVL_BUS, "%s() tr5\n", __func__); 258 259 /* Additional data at the beginning of the ring */ 260 memcpy_toio(bus->m_pdwSetRing + curr_swp, msg, sizeof(*msg)); 261 memcpy_toio(bus->m_pdwSetRing, buf, size); 262 263 } else { 264 /* Additional data wraps around the ring */ 265 memcpy_toio(bus->m_pdwSetRing + curr_swp, msg, sizeof(*msg)); 266 if (size > 0) { 267 memcpy_toio(bus->m_pdwSetRing + curr_swp + 268 sizeof(*msg), buf, space_rem - 269 sizeof(*msg)); 270 memcpy_toio(bus->m_pdwSetRing, (u8 *)buf + 271 space_rem - sizeof(*msg), 272 bytes_to_write - space_rem); 273 } 274 275 } 276 277 } /* (new_swp > bus->m_dwSizeSetRing) */ 278 else { 279 dprintk(DBGLVL_BUS, "%s() tr6\n", __func__); 280 281 /* The ring buffer doesn't wrap, two simple copies */ 282 memcpy_toio(bus->m_pdwSetRing + curr_swp, msg, sizeof(*msg)); 283 memcpy_toio(bus->m_pdwSetRing + curr_swp + sizeof(*msg), buf, 284 size); 285 } 286 287 dprintk(DBGLVL_BUS, "%s() new_swp = %x\n", __func__, new_swp); 288 289 /* Update the bus write position */ 290 saa7164_writel(bus->m_dwSetWritePos, new_swp); 291 292 /* Convert back to cpu after writing the msg to the ringbuffer. */ 293 msg->size = le16_to_cpu((__force __le16)msg->size); 294 msg->command = le32_to_cpu((__force __le32)msg->command); 295 msg->controlselector = le16_to_cpu((__force __le16)msg->controlselector); 296 ret = SAA_OK; 297 298 out: 299 saa7164_bus_dump(dev); 300 mutex_unlock(&bus->lock); 301 saa7164_bus_verify(dev); 302 return ret; 303 } 304 305 /* 306 * Receive a command or a response from the bus. The implementation does not 307 * know if it is a command or a response it simply dequeues the data, 308 * depending on the bus information given in the struct tmComResBusInfo 309 * structure. 310 * 311 * Return Value: 312 * 0 The function executed successfully. 313 * < 0 One or more members are not initialized. 314 */ 315 int saa7164_bus_get(struct saa7164_dev *dev, struct tmComResInfo* msg, 316 void *buf, int peekonly) 317 { 318 struct tmComResBusInfo *bus = &dev->bus; 319 u32 bytes_to_read, write_distance, curr_grp, curr_gwp, 320 new_grp, buf_size, space_rem; 321 struct tmComResInfo msg_tmp; 322 int ret = SAA_ERR_BAD_PARAMETER; 323 324 saa7164_bus_verify(dev); 325 326 if (msg == NULL) 327 return ret; 328 329 if (msg->size > dev->bus.m_wMaxReqSize) { 330 printk(KERN_ERR "%s() Exceeded dev->bus.m_wMaxReqSize\n", 331 __func__); 332 return ret; 333 } 334 335 if ((peekonly == 0) && (msg->size > 0) && (buf == NULL)) { 336 printk(KERN_ERR 337 "%s() Missing msg buf, size should be %d bytes\n", 338 __func__, msg->size); 339 return ret; 340 } 341 342 mutex_lock(&bus->lock); 343 344 /* Peek the bus to see if a msg exists, if it's not what we're expecting 345 * then return cleanly else read the message from the bus. 346 */ 347 curr_gwp = saa7164_readl(bus->m_dwGetWritePos); 348 curr_grp = saa7164_readl(bus->m_dwGetReadPos); 349 350 if (curr_gwp == curr_grp) { 351 ret = SAA_ERR_EMPTY; 352 goto out; 353 } 354 355 bytes_to_read = sizeof(*msg); 356 357 /* Calculate write distance to current read position */ 358 write_distance = 0; 359 if (curr_gwp >= curr_grp) 360 /* Write doesn't wrap around the ring */ 361 write_distance = curr_gwp - curr_grp; 362 else 363 /* Write wraps around the ring */ 364 write_distance = curr_gwp + bus->m_dwSizeGetRing - curr_grp; 365 366 if (bytes_to_read > write_distance) { 367 printk(KERN_ERR "%s() No message/response found\n", __func__); 368 ret = SAA_ERR_INVALID_COMMAND; 369 goto out; 370 } 371 372 /* Calculate the new read position */ 373 new_grp = curr_grp + bytes_to_read; 374 if (new_grp > bus->m_dwSizeGetRing) { 375 376 /* Ring wraps */ 377 new_grp -= bus->m_dwSizeGetRing; 378 space_rem = bus->m_dwSizeGetRing - curr_grp; 379 380 memcpy_fromio(&msg_tmp, bus->m_pdwGetRing + curr_grp, space_rem); 381 memcpy_fromio((u8 *)&msg_tmp + space_rem, bus->m_pdwGetRing, 382 bytes_to_read - space_rem); 383 384 } else { 385 /* No wrapping */ 386 memcpy_fromio(&msg_tmp, bus->m_pdwGetRing + curr_grp, bytes_to_read); 387 } 388 /* Convert from little endian to CPU */ 389 msg_tmp.size = le16_to_cpu((__force __le16)msg_tmp.size); 390 msg_tmp.command = le32_to_cpu((__force __le32)msg_tmp.command); 391 msg_tmp.controlselector = le16_to_cpu((__force __le16)msg_tmp.controlselector); 392 393 /* No need to update the read positions, because this was a peek */ 394 /* If the caller specifically want to peek, return */ 395 if (peekonly) { 396 memcpy(msg, &msg_tmp, sizeof(*msg)); 397 goto peekout; 398 } 399 400 /* Check if the command/response matches what is expected */ 401 if ((msg_tmp.id != msg->id) || (msg_tmp.command != msg->command) || 402 (msg_tmp.controlselector != msg->controlselector) || 403 (msg_tmp.seqno != msg->seqno) || (msg_tmp.size != msg->size)) { 404 405 printk(KERN_ERR "%s() Unexpected msg miss-match\n", __func__); 406 saa7164_bus_dumpmsg(dev, msg, buf); 407 saa7164_bus_dumpmsg(dev, &msg_tmp, NULL); 408 ret = SAA_ERR_INVALID_COMMAND; 409 goto out; 410 } 411 412 /* Get the actual command and response from the bus */ 413 buf_size = msg->size; 414 415 bytes_to_read = sizeof(*msg) + msg->size; 416 /* Calculate write distance to current read position */ 417 write_distance = 0; 418 if (curr_gwp >= curr_grp) 419 /* Write doesn't wrap around the ring */ 420 write_distance = curr_gwp - curr_grp; 421 else 422 /* Write wraps around the ring */ 423 write_distance = curr_gwp + bus->m_dwSizeGetRing - curr_grp; 424 425 if (bytes_to_read > write_distance) { 426 printk(KERN_ERR "%s() Invalid bus state, missing msg or mangled ring, faulty H/W / bad code?\n", 427 __func__); 428 ret = SAA_ERR_INVALID_COMMAND; 429 goto out; 430 } 431 432 /* Calculate the new read position */ 433 new_grp = curr_grp + bytes_to_read; 434 if (new_grp > bus->m_dwSizeGetRing) { 435 436 /* Ring wraps */ 437 new_grp -= bus->m_dwSizeGetRing; 438 space_rem = bus->m_dwSizeGetRing - curr_grp; 439 440 if (space_rem < sizeof(*msg)) { 441 /* msg wraps around the ring */ 442 memcpy_fromio(msg, bus->m_pdwGetRing + curr_grp, space_rem); 443 memcpy_fromio((u8 *)msg + space_rem, bus->m_pdwGetRing, 444 sizeof(*msg) - space_rem); 445 if (buf) 446 memcpy_fromio(buf, bus->m_pdwGetRing + sizeof(*msg) - 447 space_rem, buf_size); 448 449 } else if (space_rem == sizeof(*msg)) { 450 memcpy_fromio(msg, bus->m_pdwGetRing + curr_grp, sizeof(*msg)); 451 if (buf) 452 memcpy_fromio(buf, bus->m_pdwGetRing, buf_size); 453 } else { 454 /* Additional data wraps around the ring */ 455 memcpy_fromio(msg, bus->m_pdwGetRing + curr_grp, sizeof(*msg)); 456 if (buf) { 457 memcpy_fromio(buf, bus->m_pdwGetRing + curr_grp + 458 sizeof(*msg), space_rem - sizeof(*msg)); 459 memcpy_fromio(buf + space_rem - sizeof(*msg), 460 bus->m_pdwGetRing, bytes_to_read - 461 space_rem); 462 } 463 464 } 465 466 } else { 467 /* No wrapping */ 468 memcpy_fromio(msg, bus->m_pdwGetRing + curr_grp, sizeof(*msg)); 469 if (buf) 470 memcpy_fromio(buf, bus->m_pdwGetRing + curr_grp + sizeof(*msg), 471 buf_size); 472 } 473 /* Convert from little endian to CPU */ 474 msg->size = le16_to_cpu((__force __le16)msg->size); 475 msg->command = le32_to_cpu((__force __le32)msg->command); 476 msg->controlselector = le16_to_cpu((__force __le16)msg->controlselector); 477 478 /* Update the read positions, adjusting the ring */ 479 saa7164_writel(bus->m_dwGetReadPos, new_grp); 480 481 peekout: 482 ret = SAA_OK; 483 out: 484 mutex_unlock(&bus->lock); 485 saa7164_bus_verify(dev); 486 return ret; 487 } 488 489