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