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