1 /***************************************************************************
2   BCM70010 Linux driver
3   Copyright (c) 2005-2009, Broadcom Corporation.
4 
5   This driver is free software; you can redistribute it and/or modify
6   it under the terms of the GNU General Public License as published by
7   the Free Software Foundation, version 2 of the License.
8 
9   This driver is distributed in the hope that it will be useful,
10   but WITHOUT ANY WARRANTY; without even the implied warranty of
11   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12   GNU General Public License for more details.
13 
14   You should have received a copy of the GNU General Public License
15   along with this driver.  If not, see <http://www.gnu.org/licenses/>.
16 ***************************************************************************/
17 
18 #include <linux/mutex.h>
19 #include <linux/slab.h>
20 
21 #include "crystalhd_lnx.h"
22 
23 static DEFINE_MUTEX(chd_dec_mutex);
24 static struct class *crystalhd_class;
25 
26 static struct crystalhd_adp *g_adp_info;
27 
chd_dec_isr(int irq,void * arg)28 static irqreturn_t chd_dec_isr(int irq, void *arg)
29 {
30 	struct crystalhd_adp *adp = (struct crystalhd_adp *) arg;
31 	int rc = 0;
32 	if (adp)
33 		rc = crystalhd_cmd_interrupt(&adp->cmds);
34 
35 	return IRQ_RETVAL(rc);
36 }
37 
chd_dec_enable_int(struct crystalhd_adp * adp)38 static int chd_dec_enable_int(struct crystalhd_adp *adp)
39 {
40 	int rc = 0;
41 
42 	if (!adp || !adp->pdev) {
43 		BCMLOG_ERR("Invalid arg!!\n");
44 		return -EINVAL;
45 	}
46 
47 	if (adp->pdev->msi_enabled)
48 		adp->msi = 1;
49 	else
50 		adp->msi = pci_enable_msi(adp->pdev);
51 
52 	rc = request_irq(adp->pdev->irq, chd_dec_isr, IRQF_SHARED,
53 			 adp->name, (void *)adp);
54 	if (rc) {
55 		BCMLOG_ERR("Interrupt request failed..\n");
56 		pci_disable_msi(adp->pdev);
57 	}
58 
59 	return rc;
60 }
61 
chd_dec_disable_int(struct crystalhd_adp * adp)62 static int chd_dec_disable_int(struct crystalhd_adp *adp)
63 {
64 	if (!adp || !adp->pdev) {
65 		BCMLOG_ERR("Invalid arg!!\n");
66 		return -EINVAL;
67 	}
68 
69 	free_irq(adp->pdev->irq, adp);
70 
71 	if (adp->msi)
72 		pci_disable_msi(adp->pdev);
73 
74 	return 0;
75 }
76 
chd_dec_alloc_iodata(struct crystalhd_adp * adp,bool isr)77 struct crystalhd_ioctl_data *chd_dec_alloc_iodata(struct crystalhd_adp *adp, bool isr)
78 {
79 	unsigned long flags = 0;
80 	struct crystalhd_ioctl_data *temp;
81 
82 	if (!adp)
83 		return NULL;
84 
85 	spin_lock_irqsave(&adp->lock, flags);
86 
87 	temp = adp->idata_free_head;
88 	if (temp) {
89 		adp->idata_free_head = adp->idata_free_head->next;
90 		memset(temp, 0, sizeof(*temp));
91 	}
92 
93 	spin_unlock_irqrestore(&adp->lock, flags);
94 	return temp;
95 }
96 
chd_dec_free_iodata(struct crystalhd_adp * adp,struct crystalhd_ioctl_data * iodata,bool isr)97 void chd_dec_free_iodata(struct crystalhd_adp *adp, struct crystalhd_ioctl_data *iodata,
98 			 bool isr)
99 {
100 	unsigned long flags = 0;
101 
102 	if (!adp || !iodata)
103 		return;
104 
105 	spin_lock_irqsave(&adp->lock, flags);
106 	iodata->next = adp->idata_free_head;
107 	adp->idata_free_head = iodata;
108 	spin_unlock_irqrestore(&adp->lock, flags);
109 }
110 
crystalhd_user_data(unsigned long ud,void * dr,int size,int set)111 static inline int crystalhd_user_data(unsigned long ud, void *dr, int size, int set)
112 {
113 	int rc;
114 
115 	if (!ud || !dr) {
116 		BCMLOG_ERR("Invalid arg\n");
117 		return -EINVAL;
118 	}
119 
120 	if (set)
121 		rc = copy_to_user((void *)ud, dr, size);
122 	else
123 		rc = copy_from_user(dr, (void *)ud, size);
124 
125 	if (rc) {
126 		BCMLOG_ERR("Invalid args for command\n");
127 		rc = -EFAULT;
128 	}
129 
130 	return rc;
131 }
132 
chd_dec_fetch_cdata(struct crystalhd_adp * adp,struct crystalhd_ioctl_data * io,uint32_t m_sz,unsigned long ua)133 static int chd_dec_fetch_cdata(struct crystalhd_adp *adp, struct crystalhd_ioctl_data *io,
134 			       uint32_t m_sz, unsigned long ua)
135 {
136 	unsigned long ua_off;
137 	int rc = 0;
138 
139 	if (!adp || !io || !ua || !m_sz) {
140 		BCMLOG_ERR("Invalid Arg!!\n");
141 		return -EINVAL;
142 	}
143 
144 	io->add_cdata = vmalloc(m_sz);
145 	if (!io->add_cdata) {
146 		BCMLOG_ERR("kalloc fail for sz:%x\n", m_sz);
147 		return -ENOMEM;
148 	}
149 
150 	io->add_cdata_sz = m_sz;
151 	ua_off = ua + sizeof(io->udata);
152 	rc = crystalhd_user_data(ua_off, io->add_cdata, io->add_cdata_sz, 0);
153 	if (rc) {
154 		BCMLOG_ERR("failed to pull add_cdata sz:%x ua_off:%x\n",
155 			   io->add_cdata_sz, (unsigned int)ua_off);
156 		kfree(io->add_cdata);
157 		io->add_cdata = NULL;
158 		return -ENODATA;
159 	}
160 
161 	return rc;
162 }
163 
chd_dec_release_cdata(struct crystalhd_adp * adp,struct crystalhd_ioctl_data * io,unsigned long ua)164 static int chd_dec_release_cdata(struct crystalhd_adp *adp,
165 				 struct crystalhd_ioctl_data *io, unsigned long ua)
166 {
167 	unsigned long ua_off;
168 	int rc;
169 
170 	if (!adp || !io || !ua) {
171 		BCMLOG_ERR("Invalid Arg!!\n");
172 		return -EINVAL;
173 	}
174 
175 	if (io->cmd != BCM_IOC_FW_DOWNLOAD) {
176 		ua_off = ua + sizeof(io->udata);
177 		rc = crystalhd_user_data(ua_off, io->add_cdata,
178 					io->add_cdata_sz, 1);
179 		if (rc) {
180 			BCMLOG_ERR("failed to push add_cdata sz:%x ua_off:%x\n",
181 				   io->add_cdata_sz, (unsigned int)ua_off);
182 			return -ENODATA;
183 		}
184 	}
185 
186 	if (io->add_cdata) {
187 		vfree(io->add_cdata);
188 		io->add_cdata = NULL;
189 	}
190 
191 	return 0;
192 }
193 
chd_dec_proc_user_data(struct crystalhd_adp * adp,struct crystalhd_ioctl_data * io,unsigned long ua,int set)194 static int chd_dec_proc_user_data(struct crystalhd_adp *adp,
195 				  struct crystalhd_ioctl_data *io,
196 				  unsigned long ua, int set)
197 {
198 	int rc;
199 	uint32_t m_sz = 0;
200 
201 	if (!adp || !io || !ua) {
202 		BCMLOG_ERR("Invalid Arg!!\n");
203 		return -EINVAL;
204 	}
205 
206 	rc = crystalhd_user_data(ua, &io->udata, sizeof(io->udata), set);
207 	if (rc) {
208 		BCMLOG_ERR("failed to %s iodata\n", (set ? "set" : "get"));
209 		return rc;
210 	}
211 
212 	switch (io->cmd) {
213 	case BCM_IOC_MEM_RD:
214 	case BCM_IOC_MEM_WR:
215 	case BCM_IOC_FW_DOWNLOAD:
216 		m_sz = io->udata.u.devMem.NumDwords * 4;
217 		if (set)
218 			rc = chd_dec_release_cdata(adp, io, ua);
219 		else
220 			rc = chd_dec_fetch_cdata(adp, io, m_sz, ua);
221 		break;
222 	default:
223 		break;
224 	}
225 
226 	return rc;
227 }
228 
chd_dec_api_cmd(struct crystalhd_adp * adp,unsigned long ua,uint32_t uid,uint32_t cmd,crystalhd_cmd_proc func)229 static int chd_dec_api_cmd(struct crystalhd_adp *adp, unsigned long ua,
230 			   uint32_t uid, uint32_t cmd, crystalhd_cmd_proc func)
231 {
232 	int rc;
233 	struct crystalhd_ioctl_data *temp;
234 	enum BC_STATUS sts = BC_STS_SUCCESS;
235 
236 	temp = chd_dec_alloc_iodata(adp, 0);
237 	if (!temp) {
238 		BCMLOG_ERR("Failed to get iodata..\n");
239 		return -EINVAL;
240 	}
241 
242 	temp->u_id = uid;
243 	temp->cmd  = cmd;
244 
245 	rc = chd_dec_proc_user_data(adp, temp, ua, 0);
246 	if (!rc) {
247 		sts = func(&adp->cmds, temp);
248 		if (sts == BC_STS_PENDING)
249 			sts = BC_STS_NOT_IMPL;
250 		temp->udata.RetSts = sts;
251 		rc = chd_dec_proc_user_data(adp, temp, ua, 1);
252 	}
253 
254 	if (temp) {
255 		chd_dec_free_iodata(adp, temp, 0);
256 		temp = NULL;
257 	}
258 
259 	return rc;
260 }
261 
262 /* API interfaces */
chd_dec_ioctl(struct file * fd,unsigned int cmd,unsigned long ua)263 static long chd_dec_ioctl(struct file *fd, unsigned int cmd, unsigned long ua)
264 {
265 	struct crystalhd_adp *adp = chd_get_adp();
266 	crystalhd_cmd_proc cproc;
267 	struct crystalhd_user *uc;
268 	int ret;
269 
270 	if (!adp || !fd) {
271 		BCMLOG_ERR("Invalid adp\n");
272 		return -EINVAL;
273 	}
274 
275 	uc = fd->private_data;
276 	if (!uc) {
277 		BCMLOG_ERR("Failed to get uc\n");
278 		return -ENODATA;
279 	}
280 
281 	mutex_lock(&chd_dec_mutex);
282 	cproc = crystalhd_get_cmd_proc(&adp->cmds, cmd, uc);
283 	if (!cproc) {
284 		BCMLOG_ERR("Unhandled command: %d\n", cmd);
285 		mutex_unlock(&chd_dec_mutex);
286 		return -EINVAL;
287 	}
288 
289 	ret = chd_dec_api_cmd(adp, ua, uc->uid, cmd, cproc);
290 	mutex_unlock(&chd_dec_mutex);
291 	return ret;
292 }
293 
chd_dec_open(struct inode * in,struct file * fd)294 static int chd_dec_open(struct inode *in, struct file *fd)
295 {
296 	struct crystalhd_adp *adp = chd_get_adp();
297 	int rc = 0;
298 	enum BC_STATUS sts = BC_STS_SUCCESS;
299 	struct crystalhd_user *uc = NULL;
300 
301 	BCMLOG_ENTER;
302 	if (!adp) {
303 		BCMLOG_ERR("Invalid adp\n");
304 		return -EINVAL;
305 	}
306 
307 	if (adp->cfg_users >= BC_LINK_MAX_OPENS) {
308 		BCMLOG(BCMLOG_INFO, "Already in use.%d\n", adp->cfg_users);
309 		return -EBUSY;
310 	}
311 
312 	sts = crystalhd_user_open(&adp->cmds, &uc);
313 	if (sts != BC_STS_SUCCESS) {
314 		BCMLOG_ERR("cmd_user_open - %d\n", sts);
315 		rc = -EBUSY;
316 	}
317 
318 	adp->cfg_users++;
319 
320 	fd->private_data = uc;
321 
322 	return rc;
323 }
324 
chd_dec_close(struct inode * in,struct file * fd)325 static int chd_dec_close(struct inode *in, struct file *fd)
326 {
327 	struct crystalhd_adp *adp = chd_get_adp();
328 	struct crystalhd_user *uc;
329 
330 	BCMLOG_ENTER;
331 	if (!adp) {
332 		BCMLOG_ERR("Invalid adp\n");
333 		return -EINVAL;
334 	}
335 
336 	uc = fd->private_data;
337 	if (!uc) {
338 		BCMLOG_ERR("Failed to get uc\n");
339 		return -ENODATA;
340 	}
341 
342 	crystalhd_user_close(&adp->cmds, uc);
343 
344 	adp->cfg_users--;
345 
346 	return 0;
347 }
348 
349 static const struct file_operations chd_dec_fops = {
350 	.owner   = THIS_MODULE,
351 	.unlocked_ioctl = chd_dec_ioctl,
352 	.open    = chd_dec_open,
353 	.release = chd_dec_close,
354 	.llseek = noop_llseek,
355 };
356 
chd_dec_init_chdev(struct crystalhd_adp * adp)357 static int __devinit chd_dec_init_chdev(struct crystalhd_adp *adp)
358 {
359 	struct crystalhd_ioctl_data *temp;
360 	struct device *dev;
361 	int rc = -ENODEV, i = 0;
362 
363 	if (!adp)
364 		goto fail;
365 
366 	adp->chd_dec_major = register_chrdev(0, CRYSTALHD_API_NAME,
367 					     &chd_dec_fops);
368 	if (adp->chd_dec_major < 0) {
369 		BCMLOG_ERR("Failed to create config dev\n");
370 		rc = adp->chd_dec_major;
371 		goto fail;
372 	}
373 
374 	/* register crystalhd class */
375 	crystalhd_class = class_create(THIS_MODULE, "crystalhd");
376 	if (IS_ERR(crystalhd_class)) {
377 		BCMLOG_ERR("failed to create class\n");
378 		goto fail;
379 	}
380 
381 	dev = device_create(crystalhd_class, NULL, MKDEV(adp->chd_dec_major, 0),
382 			    NULL, "crystalhd");
383 	if (IS_ERR(dev)) {
384 		BCMLOG_ERR("failed to create device\n");
385 		goto device_create_fail;
386 	}
387 
388 	rc = crystalhd_create_elem_pool(adp, BC_LINK_ELEM_POOL_SZ);
389 	if (rc) {
390 		BCMLOG_ERR("failed to create device\n");
391 		goto elem_pool_fail;
392 	}
393 
394 	/* Allocate general purpose ioctl pool. */
395 	for (i = 0; i < CHD_IODATA_POOL_SZ; i++) {
396 		temp = kzalloc(sizeof(struct crystalhd_ioctl_data), GFP_KERNEL);
397 		if (!temp) {
398 			BCMLOG_ERR("ioctl data pool kzalloc failed\n");
399 			rc = -ENOMEM;
400 			goto kzalloc_fail;
401 		}
402 		/* Add to global pool.. */
403 		chd_dec_free_iodata(adp, temp, 0);
404 	}
405 
406 	return 0;
407 
408 kzalloc_fail:
409 	crystalhd_delete_elem_pool(adp);
410 elem_pool_fail:
411 	device_destroy(crystalhd_class, MKDEV(adp->chd_dec_major, 0));
412 device_create_fail:
413 	class_destroy(crystalhd_class);
414 fail:
415 	return rc;
416 }
417 
chd_dec_release_chdev(struct crystalhd_adp * adp)418 static void __devexit chd_dec_release_chdev(struct crystalhd_adp *adp)
419 {
420 	struct crystalhd_ioctl_data *temp = NULL;
421 	if (!adp)
422 		return;
423 
424 	if (adp->chd_dec_major > 0) {
425 		/* unregister crystalhd class */
426 		device_destroy(crystalhd_class, MKDEV(adp->chd_dec_major, 0));
427 		unregister_chrdev(adp->chd_dec_major, CRYSTALHD_API_NAME);
428 		BCMLOG(BCMLOG_INFO, "released api device - %d\n",
429 		       adp->chd_dec_major);
430 		class_destroy(crystalhd_class);
431 	}
432 	adp->chd_dec_major = 0;
433 
434 	/* Clear iodata pool.. */
435 	do {
436 		temp = chd_dec_alloc_iodata(adp, 0);
437 		kfree(temp);
438 	} while (temp);
439 
440 	crystalhd_delete_elem_pool(adp);
441 }
442 
chd_pci_reserve_mem(struct crystalhd_adp * pinfo)443 static int __devinit chd_pci_reserve_mem(struct crystalhd_adp *pinfo)
444 {
445 	int rc;
446 	unsigned long bar2 = pci_resource_start(pinfo->pdev, 2);
447 	uint32_t mem_len   = pci_resource_len(pinfo->pdev, 2);
448 	unsigned long bar0 = pci_resource_start(pinfo->pdev, 0);
449 	uint32_t i2o_len   = pci_resource_len(pinfo->pdev, 0);
450 
451 	BCMLOG(BCMLOG_SSTEP, "bar2:0x%lx-0x%08x  bar0:0x%lx-0x%08x\n",
452 	       bar2, mem_len, bar0, i2o_len);
453 
454 	rc = check_mem_region(bar2, mem_len);
455 	if (rc) {
456 		BCMLOG_ERR("No valid mem region...\n");
457 		return -ENOMEM;
458 	}
459 
460 	pinfo->addr = ioremap_nocache(bar2, mem_len);
461 	if (!pinfo->addr) {
462 		BCMLOG_ERR("Failed to remap mem region...\n");
463 		return -ENOMEM;
464 	}
465 
466 	pinfo->pci_mem_start = bar2;
467 	pinfo->pci_mem_len   = mem_len;
468 
469 	rc = check_mem_region(bar0, i2o_len);
470 	if (rc) {
471 		BCMLOG_ERR("No valid mem region...\n");
472 		return -ENOMEM;
473 	}
474 
475 	pinfo->i2o_addr = ioremap_nocache(bar0, i2o_len);
476 	if (!pinfo->i2o_addr) {
477 		BCMLOG_ERR("Failed to remap mem region...\n");
478 		return -ENOMEM;
479 	}
480 
481 	pinfo->pci_i2o_start = bar0;
482 	pinfo->pci_i2o_len   = i2o_len;
483 
484 	rc = pci_request_regions(pinfo->pdev, pinfo->name);
485 	if (rc < 0) {
486 		BCMLOG_ERR("Region request failed: %d\n", rc);
487 		return rc;
488 	}
489 
490 	BCMLOG(BCMLOG_SSTEP, "Mapped addr:0x%08lx  i2o_addr:0x%08lx\n",
491 	       (unsigned long)pinfo->addr, (unsigned long)pinfo->i2o_addr);
492 
493 	return 0;
494 }
495 
chd_pci_release_mem(struct crystalhd_adp * pinfo)496 static void __devexit chd_pci_release_mem(struct crystalhd_adp *pinfo)
497 {
498 	if (!pinfo)
499 		return;
500 
501 	if (pinfo->addr)
502 		iounmap(pinfo->addr);
503 
504 	if (pinfo->i2o_addr)
505 		iounmap(pinfo->i2o_addr);
506 
507 	pci_release_regions(pinfo->pdev);
508 }
509 
510 
chd_dec_pci_remove(struct pci_dev * pdev)511 static void __devexit chd_dec_pci_remove(struct pci_dev *pdev)
512 {
513 	struct crystalhd_adp *pinfo;
514 	enum BC_STATUS sts = BC_STS_SUCCESS;
515 
516 	BCMLOG_ENTER;
517 
518 	pinfo = pci_get_drvdata(pdev);
519 	if (!pinfo) {
520 		BCMLOG_ERR("could not get adp\n");
521 		return;
522 	}
523 
524 	sts = crystalhd_delete_cmd_context(&pinfo->cmds);
525 	if (sts != BC_STS_SUCCESS)
526 		BCMLOG_ERR("cmd delete :%d\n", sts);
527 
528 	chd_dec_release_chdev(pinfo);
529 
530 	chd_dec_disable_int(pinfo);
531 
532 	chd_pci_release_mem(pinfo);
533 	pci_disable_device(pinfo->pdev);
534 
535 	kfree(pinfo);
536 	g_adp_info = NULL;
537 }
538 
chd_dec_pci_probe(struct pci_dev * pdev,const struct pci_device_id * entry)539 static int __devinit chd_dec_pci_probe(struct pci_dev *pdev,
540 			     const struct pci_device_id *entry)
541 {
542 	struct crystalhd_adp *pinfo;
543 	int rc;
544 	enum BC_STATUS sts = BC_STS_SUCCESS;
545 
546 	BCMLOG(BCMLOG_DBG, "PCI_INFO: Vendor:0x%04x Device:0x%04x "
547 	       "s_vendor:0x%04x s_device: 0x%04x\n",
548 	       pdev->vendor, pdev->device, pdev->subsystem_vendor,
549 	       pdev->subsystem_device);
550 
551 	pinfo = kzalloc(sizeof(struct crystalhd_adp), GFP_KERNEL);
552 	if (!pinfo) {
553 		BCMLOG_ERR("Failed to allocate memory\n");
554 		return -ENOMEM;
555 	}
556 
557 	pinfo->pdev = pdev;
558 
559 	rc = pci_enable_device(pdev);
560 	if (rc) {
561 		BCMLOG_ERR("Failed to enable PCI device\n");
562 		goto err;
563 	}
564 
565 	snprintf(pinfo->name, sizeof(pinfo->name), "crystalhd_pci_e:%d:%d:%d",
566 		 pdev->bus->number, PCI_SLOT(pdev->devfn),
567 		 PCI_FUNC(pdev->devfn));
568 
569 	rc = chd_pci_reserve_mem(pinfo);
570 	if (rc) {
571 		BCMLOG_ERR("Failed to setup memory regions.\n");
572 		pci_disable_device(pdev);
573 		rc = -ENOMEM;
574 		goto err;
575 	}
576 
577 	pinfo->present	= 1;
578 	pinfo->drv_data = entry->driver_data;
579 
580 	/* Setup adapter level lock.. */
581 	spin_lock_init(&pinfo->lock);
582 
583 	/* setup api stuff.. */
584 	chd_dec_init_chdev(pinfo);
585 	rc = chd_dec_enable_int(pinfo);
586 	if (rc) {
587 		BCMLOG_ERR("_enable_int err:%d\n", rc);
588 		pci_disable_device(pdev);
589 		rc = -ENODEV;
590 		goto err;
591 	}
592 
593 	/* Set dma mask... */
594 	if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) {
595 		pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64));
596 		pinfo->dmabits = 64;
597 	} else if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) {
598 		pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
599 		pinfo->dmabits = 32;
600 	} else {
601 		BCMLOG_ERR("Unabled to setup DMA %d\n", rc);
602 		pci_disable_device(pdev);
603 		rc = -ENODEV;
604 		goto err;
605 	}
606 
607 	sts = crystalhd_setup_cmd_context(&pinfo->cmds, pinfo);
608 	if (sts != BC_STS_SUCCESS) {
609 		BCMLOG_ERR("cmd setup :%d\n", sts);
610 		pci_disable_device(pdev);
611 		rc = -ENODEV;
612 		goto err;
613 	}
614 
615 	pci_set_master(pdev);
616 
617 	pci_set_drvdata(pdev, pinfo);
618 
619 	g_adp_info = pinfo;
620 
621 	return 0;
622 
623 err:
624 	kfree(pinfo);
625 	return rc;
626 }
627 
628 #ifdef CONFIG_PM
chd_dec_pci_suspend(struct pci_dev * pdev,pm_message_t state)629 int chd_dec_pci_suspend(struct pci_dev *pdev, pm_message_t state)
630 {
631 	struct crystalhd_adp *adp;
632 	struct crystalhd_ioctl_data *temp;
633 	enum BC_STATUS sts = BC_STS_SUCCESS;
634 
635 	adp = pci_get_drvdata(pdev);
636 	if (!adp) {
637 		BCMLOG_ERR("could not get adp\n");
638 		return -ENODEV;
639 	}
640 
641 	temp = chd_dec_alloc_iodata(adp, false);
642 	if (!temp) {
643 		BCMLOG_ERR("could not get ioctl data\n");
644 		return -ENODEV;
645 	}
646 
647 	sts = crystalhd_suspend(&adp->cmds, temp);
648 	if (sts != BC_STS_SUCCESS) {
649 		BCMLOG_ERR("BCM70012 Suspend %d\n", sts);
650 		return -ENODEV;
651 	}
652 
653 	chd_dec_free_iodata(adp, temp, false);
654 	chd_dec_disable_int(adp);
655 	pci_save_state(pdev);
656 
657 	/* Disable IO/bus master/irq router */
658 	pci_disable_device(pdev);
659 	pci_set_power_state(pdev, pci_choose_state(pdev, state));
660 	return 0;
661 }
662 
chd_dec_pci_resume(struct pci_dev * pdev)663 int chd_dec_pci_resume(struct pci_dev *pdev)
664 {
665 	struct crystalhd_adp *adp;
666 	enum BC_STATUS sts = BC_STS_SUCCESS;
667 	int rc;
668 
669 	adp = pci_get_drvdata(pdev);
670 	if (!adp) {
671 		BCMLOG_ERR("could not get adp\n");
672 		return -ENODEV;
673 	}
674 
675 	pci_set_power_state(pdev, PCI_D0);
676 	pci_restore_state(pdev);
677 
678 	/* device's irq possibly is changed, driver should take care */
679 	if (pci_enable_device(pdev)) {
680 		BCMLOG_ERR("Failed to enable PCI device\n");
681 		return 1;
682 	}
683 
684 	pci_set_master(pdev);
685 
686 	rc = chd_dec_enable_int(adp);
687 	if (rc) {
688 		BCMLOG_ERR("_enable_int err:%d\n", rc);
689 		pci_disable_device(pdev);
690 		return -ENODEV;
691 	}
692 
693 	sts = crystalhd_resume(&adp->cmds);
694 	if (sts != BC_STS_SUCCESS) {
695 		BCMLOG_ERR("BCM70012 Resume %d\n", sts);
696 		pci_disable_device(pdev);
697 		return -ENODEV;
698 	}
699 
700 	return 0;
701 }
702 #endif
703 
704 static DEFINE_PCI_DEVICE_TABLE(chd_dec_pci_id_table) = {
705 	{ PCI_VDEVICE(BROADCOM, 0x1612), 8 },
706 	{ 0, },
707 };
708 MODULE_DEVICE_TABLE(pci, chd_dec_pci_id_table);
709 
710 static struct pci_driver bc_chd_70012_driver = {
711 	.name     = "Broadcom 70012 Decoder",
712 	.probe    = chd_dec_pci_probe,
713 	.remove   = __devexit_p(chd_dec_pci_remove),
714 	.id_table = chd_dec_pci_id_table,
715 #ifdef CONFIG_PM
716 	.suspend  = chd_dec_pci_suspend,
717 	.resume   = chd_dec_pci_resume
718 #endif
719 };
720 
chd_set_log_level(struct crystalhd_adp * adp,char * arg)721 void chd_set_log_level(struct crystalhd_adp *adp, char *arg)
722 {
723 	if ((!arg) || (strlen(arg) < 3))
724 		g_linklog_level = BCMLOG_ERROR | BCMLOG_DATA;
725 	else if (!strncmp(arg, "sstep", 5))
726 		g_linklog_level = BCMLOG_INFO | BCMLOG_DATA | BCMLOG_DBG |
727 				  BCMLOG_SSTEP | BCMLOG_ERROR;
728 	else if (!strncmp(arg, "info", 4))
729 		g_linklog_level = BCMLOG_ERROR | BCMLOG_DATA | BCMLOG_INFO;
730 	else if (!strncmp(arg, "debug", 5))
731 		g_linklog_level = BCMLOG_ERROR | BCMLOG_DATA | BCMLOG_INFO |
732 				  BCMLOG_DBG;
733 	else if (!strncmp(arg, "pball", 5))
734 		g_linklog_level = 0xFFFFFFFF & ~(BCMLOG_SPINLOCK);
735 	else if (!strncmp(arg, "silent", 6))
736 		g_linklog_level = 0;
737 	else
738 		g_linklog_level = 0;
739 }
740 
chd_get_adp(void)741 struct crystalhd_adp *chd_get_adp(void)
742 {
743 	return g_adp_info;
744 }
745 
chd_dec_module_init(void)746 static int __init chd_dec_module_init(void)
747 {
748 	int rc;
749 
750 	chd_set_log_level(NULL, "debug");
751 	BCMLOG(BCMLOG_DATA, "Loading crystalhd %d.%d.%d\n",
752 	       crystalhd_kmod_major, crystalhd_kmod_minor, crystalhd_kmod_rev);
753 
754 	rc = pci_register_driver(&bc_chd_70012_driver);
755 
756 	if (rc < 0)
757 		BCMLOG_ERR("Could not find any devices. err:%d\n", rc);
758 
759 	return rc;
760 }
761 module_init(chd_dec_module_init);
762 
chd_dec_module_cleanup(void)763 static void __exit chd_dec_module_cleanup(void)
764 {
765 	BCMLOG(BCMLOG_DATA, "unloading crystalhd %d.%d.%d\n",
766 	       crystalhd_kmod_major, crystalhd_kmod_minor, crystalhd_kmod_rev);
767 
768 	pci_unregister_driver(&bc_chd_70012_driver);
769 }
770 module_exit(chd_dec_module_cleanup);
771 
772 MODULE_AUTHOR("Naren Sankar <nsankar@broadcom.com>");
773 MODULE_AUTHOR("Prasad Bolisetty <prasadb@broadcom.com>");
774 MODULE_DESCRIPTION(CRYSTAL_HD_NAME);
775 MODULE_LICENSE("GPL");
776 MODULE_ALIAS("bcm70012");
777